#ifndef __PCAN_MAIN_H__
#define __PCAN_MAIN_H__

//****************************************************************************
// Copyright (C) 2001,2002,2003,2004  PEAK System-Technik GmbH
//
// linux@peak-system.com
// www.peak-system.com
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// Maintainer(s): Klaus Hitschler (klaus.hitschler@gmx.de)
//
// Contributions: Marcel Offermans (marcel.offermans@luminis.nl)
//                Philipp Baer (philipp.baer@informatik.uni-ulm.de)
//****************************************************************************

//****************************************************************************
//
// pcan_main.h - global defines to include in all files this module is made of
//
// $Log: pcan_main.h,v $
// Revision 1.50  2004/05/02 12:06:02  klaus
// total rebuild of Makefile for KBUILD support for Kernel 2.6
//
// Revision 1.49  2004/04/11 22:03:29  klaus
// cosmetic changes
//
// Revision 1.48  2004/04/10 12:25:39  klaus
// merge polished between HEAD and kernel-2.6 branch
//
// Revision 1.47  2004/04/10 08:57:26  klaus
// merge finished between HEAD and kernel-2.6 branch
//
// Revision 1.44.2.1  2004/03/21 12:09:09  klaus
// first commit for branch to kernel 2.6 code
//
// Revision 1.46  2004/03/27 16:57:06  klaus
// modified for use with kernels <= 2.2.14
//
// Revision 1.45  2004/03/27 15:10:54  klaus
// prepared for use with gcc 3.x, modified for use with kernels < 2.2.4
//
// Revision 1.44  2003/06/22 15:34:51  klaus
// added parts to support devfs provided by Philipp Baer (partially untested)
//
// Revision 1.43  2003/06/04 19:26:15  klaus
// adapted to kernel 2.5.69 using GCC 3.2.3 (marcel), released release_20030604_x
//
// Revision 1.40  2003/04/22 17:36:59  klaus
// now covers kernel 2.4.19
//
// Revision 1.39  2003/03/02 10:58:07  klaus
// merged USB thread into main path
//
// Revision 1.38  2003/03/02 10:58:07  klaus
// merged USB thread into main path
//
// Revision 1.37.2.23  2003/02/16 19:55:52  klaus
// USB Integration, first non public release
//
// Revision 1.37.2.22  2003/02/16 16:36:16  klaus
// pcan_usb_kernel.c returned to main modules
//
// Revision 1.37.2.21  2003/02/09 10:29:20  klaus
// code cleanup, Release_20030208_x
//
// Revision 1.37.2.20  2003/02/08 17:32:43  klaus
// modified to use pcan_usb_kernel as proprietary module
//
// Revision 1.37.2.19  2003/01/29 20:34:20  klaus
// release_20030129_a and release_20030129_u released
//
// Revision 1.37.2.18  2003/01/29 20:34:20  klaus
// release_20030129_a and release_20030129_u released
//
// Revision 1.37.2.17  2003/01/28 23:28:26  klaus
// reorderd pcan_usb.c and pcan_usb_kernel.c, tidied up
//
// Revision 1.37.2.16  2003/01/26 22:35:39  klaus
// it's not allowed to invoke 2 waits for bulk transfer at the same pipe at the same time
//
//****************************************************************************

//----------------------------------------------------------------------------
// INCLUDES
#include <src/pcan_common.h>

#include <linux/types.h>
#include <linux/list.h>
#include <linux/wait.h>

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,15)
#include <asm/spinlock.h>
#else
#include <linux/spinlock.h>
#endif

#include <asm/atomic.h>

#ifdef DEVFS_SUPPORT
#include <linux/devfs_fs_kernel.h>
#endif

#ifdef PARPORT_SUBSYSTEM
#include <linux/parport.h>
#endif

#ifdef USB_SUPPORT
#include <linux/usb.h>

#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,19)
typedef struct urb urb_t, *purb_t;
#endif

#endif

#include <pcan.h>

//----------------------------------------------------------------------------
// DEFINES
#define CHANNEL_SINGLE 0                                   // this is a single channel device
#define CHANNEL_MASTER 1                                   // multi channel device, this device is master
#define CHANNEL_SLAVE  2                                   // multi channel device, this is slave

#define READBUFFER_SIZE      80                            // buffers used in read and write call
#define WRITEBUFFER_SIZE     80
#define PCAN_MAJOR            0                            // use dynamic major allocation, else use 91
#define DEVICE_NAME      "pcan"                            // the name of the module and the proc entry
#define READ_MESSAGE_COUNT  500                            // max read message count
#define WRITE_MESSAGE_COUNT  50                            // max write message count

#ifdef DEVFS_SUPPORT
#define PCAN_DEVFS_DIR    "can"                            // name of directory containing symlinks
#endif

// parameter wBTR0BTR1
// bitrate codes of BTR0/BTR1 registers
#define CAN_BAUD_1M     0x0014                             //   1 MBit/s
#define CAN_BAUD_500K   0x001C                             // 500 kBit/s
#define CAN_BAUD_250K   0x011C                             // 250 kBit/s
#define CAN_BAUD_125K   0x031C                             // 125 kBit/s
#define CAN_BAUD_100K   0x432F                             // 100 kBit/s
#define CAN_BAUD_50K    0x472F                             //  50 kBit/s
#define CAN_BAUD_20K    0x532F                             //  20 kBit/s
#define CAN_BAUD_10K    0x672F                             //  10 kBit/s
#define CAN_BAUD_5K     0x7F7F                             //   5 kBit/s

// maximum allocated number of endpoints (w.o. control endpoints) of pcan-usb
#define PCAN_USB_MAX_ENDPOINTS 4

typedef struct
{
  u16        wStepSize;                                    // size of bytes to step to next entry
  u16        wCopySize;                                    // size of bytes to copy
  void       *bufferBegin;                                 // points to first element
  void       *bufferEnd;                                   // points to the last element
  int        nCount;                                       // max count of elements in fifo
  int        nStored;                                      // count of currently received and stored messages
  u32        dwTotal;                                      // received messages
  void       *r;                                           // points to the next Msg to read into the read buffer
  void       *w;                                           // points to the next Msg to write into read buffer
  spinlock_t lock;                                         // mutual exclusion lock
  unsigned long flags;                                     // used by spin_lock_irqsave(..);
  u8         bPutClaimed;                                  // set, if claimed for put
  u8         bGetClaimed;                                  // set, if claimed for get
} FIFO_MANAGER;

typedef struct
{
  u32  dwPort;                                             // the port of the transport layer
  u32  dwConfigPort;                                       // the confiuration port, PCI only
  void *pvVirtPort;                                        // virtual address of port
  void *pvVirtConfigPort;                                  // only PCI, the virtual address of the config port
  u16  wIrq;                                               // the associated irq level
  u8   ucMasterDevice;                                     // until now only for PCI if the 1st control 2nd chip  
} PCI_PORT;

typedef struct
{
  u32  dwPort;                                             // the port of the transport layer
  u16  wIrq;                                               // the associated irq 
  #ifdef PARPORT_SUBSYSTEM
  struct pardevice *pardev;                                // points to the associated parallel port (PARPORT subsytem)
  #endif
  u16  wEcr;                                               // ECR register in case of EPP
  u8   ucOldDataContent;                                   // the overwritten contents of the port registers
  u8   ucOldControlContent;
  u8   ucOldECRContent;
} DONGLE_PORT;

typedef struct
{
  u32  dwPort;                                             // the port of the transport layer
  u16  wIrq;                                               // the associated irq level
} ISA_PORT;

#ifdef USB_SUPPORT
typedef struct
{
  u8  ucNumber;                                            // number (or address) of endpoint
  u16 wDataSz;                                             // supported max data transfer length
} PCAN_ENDPOINT;

typedef struct
{
  struct usb_device *usb_dev;                              // the origin pointer to my USB device from kernel
  PCAN_ENDPOINT Endpoint[PCAN_USB_MAX_ENDPOINTS];          // current endpoint numbers and sizes
  u32    dwSerialNumber;                                   // Serial number of device
  u8     ucHardcodedDevNr;                                 // ascending number stored in device to distinguish after hotplug
  u8     ucRevision;                                       // the revision number of the device
  wait_queue_head_t	usb_wait_queue;                        // wait queue for usb transactions concerning this device
  spinlock_t lock;                                         // for save start and stop of services
  atomic_t active_urbs;                                    // not all active urbs for this device

	atomic_t param_xmit_finished;                            // flag set when parameter read is finished
  purb_t   param_urb;                                      // URB structure for parameter read

  purb_t   read_data;                                      // pointer to read data urb
  u8       *pucReadBuffer[2];                              // read data transfer buffer for toggle
  u16      wReadBufferLength;                              // *used* read buffer length

  purb_t   write_data;                                     // pointer to write data urb
  u8       *pucWriteBuffer;                                // buffer for to write data (OUT)
  u32      dwTelegramCount;                                // counter for telegrams

  void     *pvXptr;                                        // ptr to X
} USB_PORT;
#endif // USB_SUPPORT

typedef struct pcandev
{
  struct list_head list;                                   // link anchor for list of devices
  int  nOpenPaths;                                         // number of open paths linked to the device
  u16  wInitStep;                                          // device specific init state
  int  nMinor;                                             // the associated minor
  char *type;                                              // the literal type of the device, info only
  u16  wType;                                              // (number type) to distinguish sp and epp

  #ifdef DEVFS_SUPPORT
  devfs_handle_t devfs_candev;                             // handle to structure containing info about device file entry
  #endif

  union
  {
    DONGLE_PORT dng;                                       // private data of the various ports
    ISA_PORT    isa;
    PCI_PORT    pci;
    #ifdef USB_SUPPORT
    USB_PORT    usb;
    #endif
  } port;

  u8   (*readreg)(struct pcandev *dev, u8 port);           // read a register
  void (*writereg)(struct pcandev *dev, u8 port, u8 data); // write a register
  int  (*cleanup)(struct pcandev *dev);                    // cleanup the interface
  int  (*open)(struct pcandev *dev);                       // called at open of a path
  int  (*release)(struct pcandev *dev);                    // called at release of a path
  int  (*req_irq)(struct pcandev *dev);                    // install the interrupt handler
  void (*free_irq)(struct pcandev *dev);                   // release the interrupt

  int  (*device_open)(struct pcandev *dev, u16 btr0btr1, u8 bExtended, u8 bListenOnly); // open the device itself
  void (*device_release)(struct pcandev *dev);             // release the device itself
  int  (*device_write)(struct pcandev *dev);               // write the device

  wait_queue_head_t read_queue;                            // read process wait queue anchor
  wait_queue_head_t write_queue;                           // write process wait queue anchor

  u8   bExtended;                                          // if 0, no extended frames are accepted
  u32  *pdwInitTime;                                       // time in msec when init was called  
  int  nLastError;                                         // last error written
  u32  dwErrorCounter;                                     // counts all fatal errors
  u32  dwInterruptCounter;                                 // counts all interrupts
  u16  wCANStatus;                                         // status of CAN chip
  u16  wBTR0BTR1;                                          // the persistent storage for BTR0 and BTR1
  u8   ucCANMsgType;                                       // the persistent storage for 11 or 29 bit identifier
  u8   ucListenOnly;                                       // the persistent storage for listen-only mode
  u8   ucPhysicallyInstalled;                              // the device is PhysicallyInstalled
  atomic_t DataSendReady;                                  // !=0 if all data are send

  FIFO_MANAGER readFifo;                                   // manages the read fifo
  FIFO_MANAGER writeFifo;                                  // manages the write fifo
  TPCANRdMsg rMsg[READ_MESSAGE_COUNT];                     // all read messages
  TPCANMsg   wMsg[WRITE_MESSAGE_COUNT];                    // all write messages
} PCANDEV;

typedef struct fileobj
{
  struct pcandev *dev;                                     // pointer to related device
  u8     pcReadBuffer[READBUFFER_SIZE];                    // buffer used in read() call
  u8     *pcReadPointer;                                   // points into current read data rest
  int    nReadRest;                                        // rest of data left to read
  int    nTotalReadCount;                                  // for test only
  u8     pcWriteBuffer[WRITEBUFFER_SIZE];                  // buffer used in write() call
  u8     *pcWritePointer;                                  // work pointer into buffer
  int    nWriteCount;                                      // count of written data bytes
} FILEOBJ;

typedef struct driverobj
{
  int nMajor;                                              // the major number of Pcan interfaces
  u16 wDeviceCount;                                        // count of found devices
  u16 wInitStep;                                           // driver specific init state
  u32 dwInitTime;                                          // time in msec when init was called  
  struct list_head devices;                                // base of list of devices
  u8  *szVersionString;                                    // pointer to the driver version string
  #ifdef USB_SUPPORT
  struct usb_driver usbdrv;                                // usb driver structure
  #endif
  
  #ifdef DEVFS_SUPPORT
  devfs_handle_t devfs_candir;                             // handle to structure containing info about device file directory
  #endif
} DRIVEROBJ;

//----------------------------------------------------------------------------
// the global driver object
extern struct driverobj pcan_drv;

//----------------------------------------------------------------------------
// exported functions - not to Linux kernel!
u32  get_mtime(void); // request time in msec
void pcan_soft_init(struct pcandev *dev, char *szType, u16 wType);
void buffer_dump(u8 *pucBuffer, u16 wLineCount);

#ifdef DEVFS_SUPPORT
int pcan_devfs_register(struct pcandev *dev);
void pcan_devfs_unregister(struct pcandev *dev);
#endif

#endif // __PCAN_MAIN_H__

